package org.lc.platform.db.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.lc.platform.db.aspect.annotation.DataSource;
import org.lc.platform.db.data.DynamicDataSource;
import org.lc.platform.db.enums.DataSourceNames;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


/**
 * 多数据源，切面处理类
 */
@Aspect
@Component
public class DataSourceAspect implements Ordered {

    /*
     * @annotation匹配指定注解的方法
     * @within匹配指定注解的类
     * 注意：这里只拦截所注解的类，如果调用的是父类的方法，那么不会拦截，除非父类方法在子类中被覆盖。
     */
    @Pointcut("@annotation(org.lc.platform.db.aspect.annotation.DataSource) || @within(org.lc.platform.db.aspect.annotation.DataSource)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Class<?> dataClass = Class.forName(signature.getDeclaringTypeName());

        DataSource dsMethod = method.getAnnotation(DataSource.class);
        DataSource dsClass = dataClass.getAnnotation(DataSource.class);
        if(dsMethod != null){
            //方法优先，如果方法上存在注解，则优先使用方法上的注解
            DynamicDataSource.setDataSource(dsMethod.value());
            System.out.println("set datasource is " + dsMethod.value());
        }else if(dsClass != null){
            //其次类优先，如果类上存在注解，则使用类上的注解
            DynamicDataSource.setDataSource(dsClass.value());
            System.out.println("set datasource is " + dsClass.value());
        }else{
            //如果都不存在，则使用默认
            DynamicDataSource.setDataSource(DataSourceNames.MASTER.getValue());
            System.out.println("set datasource is " + DataSourceNames.MASTER.getValue());
        }
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            System.out.println("clean datasource");
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
